package com.thiswhyme.vc.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.servlet.mvc.condition.RequestCondition;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by thiswhyme on 2021-01-18.
 */
@Slf4j
public class ApiCondition implements RequestCondition<ApiCondition> {

    public static ApiCondition empty = new ApiCondition(ApiConverter.convert(ApiVersionConstant.DEFAULT_VERSION));

    private ApiItem version;

    private boolean NULL;

    public ApiCondition(ApiItem item) {
        this.version = item;
    }

    public ApiCondition(ApiItem item, boolean NULL) {
        this.version = item;
        this.NULL = NULL;
    }

    /**
     * <pre>
     *     Spring先扫描方法再扫描类，然后调用{@link #combine}
     *     按照方法上的注解优先级大于类上注解的原则处理，但是要注意如果方法上不定义注解的情况。
     *     如果方法或者类上不定义注解，我们会给一个默认的值{@code empty},{@link ApiHandlerMapping}
     * </pre>
     * @param other 方法扫描封装结果
     * @return
     */
    @Override
    public ApiCondition combine(ApiCondition other) {
        // 选择版本最大的接口
        if (other.NULL) {
            return this;
        }
        return other;
    }

    @Override
    public ApiCondition getMatchingCondition(HttpServletRequest request) {
        if (CorsUtils.isPreFlightRequest(request)) {
            return empty;
        }
        String version = request.getHeader(ApiVersionConstant.API_VERSION);
        // 获取所有小于等于版本的接口;如果前端不指定版本号，则默认请求1.0.0版本的接口
        if (StringUtils.isEmpty(version)) {
            log.warn("未指定版本，使用默认1.0.0版本。");
            version = ApiVersionConstant.DEFAULT_VERSION;
        }
        ApiItem item = ApiConverter.convert(version);
        if (item.compareTo(ApiItem.API_ITEM_DEFAULT) < 0) {
            throw new IllegalArgumentException(String.format("API版本[%s]错误，最低版本[%s]", version, ApiVersionConstant.DEFAULT_VERSION));
        }
        if (item.compareTo(this.version) >= 0) {
            return this;
        }
        return null;
    }

    @Override
    public int compareTo(ApiCondition other, HttpServletRequest request) {
        // 获取到多个符合条件的接口后，会按照这个排序，然后get(0)获取最大版本对应的接口.自定义条件会最后比较
        int compare = other.version.compareTo(this.version);
        if (compare == 0) {
            log.warn("RequestMappingInfo相同，请检查！version:{}", other.version);
        }
        return compare;
    }

}
